using UnityEngine;

namespace DL.Tools
{
    public class DevelopmentToos
    {
        
        /// <summary>
        /// 计算目标方向
        /// </summary>
        /// <param name="target">目标</param>
        /// <param name="self">自身</param>
        /// <param name="normal">是否归一化向量</param>
        /// <returns></returns>
        public static Vector3 CalculateDirection(Transform target, Transform self,bool normal=true)
        {
            if (normal)
            {
                return (target.position - self.position).normalized;
            }

            return (target.position - self.position);
        }

        /// <summary>
        /// 返回于目标之间的距离
        /// </summary>
        /// <param name="target"></param>
        /// <param name="self"></param>
        /// <returns></returns>
        public static float CalculateDistance(Transform target, Transform self)
        {
            return Vector3.Distance(target.position, self.position);
        }

        /// <summary>
        /// 获取增量角
        /// </summary>
        /// <param name="currentDirection">当前移动方向</param>
        /// <param name="targetDirection">目标移动方向</param>
        /// <returns></returns>
        public static float GetDeltaAngle(Transform currentDirection, Vector3 targetDirection)
        {
            //当前角色朝向的角度
            //不完全等同于欧拉角的y，因为单纯的欧拉角在斜坡并不是我们想要的
            float angleCurrent = Mathf.Atan2(currentDirection.forward.x, currentDirection.forward.z) * Mathf.Rad2Deg;
            //目标方向的角度也就是希望角色转过去的那个方向的角度
            float targetAngle = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg;

            return Mathf.DeltaAngle(angleCurrent, targetAngle);
        }

        /// <summary>
        /// 计算当前朝向于目标方向之间的夹角
        /// </summary>
        /// <param name="target"></param>
        /// <param name="self"></param>
        /// <returns></returns>
        public static float GetAngleForTargetDirection(Transform target, Transform self)
        {
            return Vector3.Angle(((self.position - target.position).normalized), self.forward);
        }

        /// <summary>
        /// 限制一个值或者度数在-360-360之间
        /// </summary>
        /// <param name="f"></param>
        /// <returns></returns>
        public static float ClampValueOn360(float f)
        {
            f %= 360f;
            if (f < 0)
                f += 360;

            return f;
        }

        /// <summary>
        /// 限制一个值或者度数在-180-180之间
        /// </summary>
        /// <param name="f"></param>
        /// <returns></returns>
        public static float ClampValueOn180(float f)
        {
            f = (f + 180f) % 360f - 180f;

            if (f < -180)
                f += 360;

            return f;
        }

        /// <summary>
        /// 从当前位置移动到目标位置
        /// 计算当前点和目标点之间的位置，移动不超过maxDistanceDelta指定的距离。
        /// </summary>
        /// <param name="target"></param>
        /// <param name="self"></param>
        /// <returns></returns>
        public static Vector3 TargetPositionOffset(Transform target, Transform self, float time)
        {
            var pos = target.transform.position;
            return Vector3.MoveTowards(self.position, pos, UnTetheredLerp(time));
        }

        /// <summary>
        /// 知一个基向量和点乘值求夹角
        /// 要求另外一个向量为基向量
        /// </summary>
        /// <param name="dot"></param>
        /// <param name="baseVec"></param>
        /// <returns></returns>
        public static float GetAngleForBasisVector3(float dot,Vector3 baseVec)
        {
            return (Mathf.Acos(dot / baseVec.magnitude) * Mathf.Rad2Deg);
        }

        /// <summary>
        /// 计算两个向量的夹角度数
        /// </summary>
        /// <param name="direction1"></param>
        /// <param name="direction2"></param>
        /// <returns></returns>
        public static float CalculateAngle(Vector3 direction1, Vector3 direction2)
        {
            return Vector3.Angle(direction1, direction2);
        }

        /// <summary>
        /// 计算两个向量的增量角
        /// </summary>
        /// <param name="rFrom">即当前的向量</param>
        /// <param name="rTo">目标向量</param>
        /// <returns></returns>
        public static float CalculateDeltaAngle(Vector3 rFrom,Vector3 rTo)
        {
            //反正切求出当前向量的角度
            float current = Mathf.Atan2(rFrom.x, rFrom.z) * Mathf.Rad2Deg;
            //反正切求出目标向量的角度
            float target = Mathf.Atan2(rTo.x, rTo.z) * Mathf.Rad2Deg;
            //通过两个角度的计算得出差异(即目标角度减去当前角度得到他们的差异值)
            return Mathf.DeltaAngle(current, target);
        }

        #region 数学

        /// <summary>
        /// 不受帧数影响的Lerp
        /// </summary>
        /// <param name="time">平滑时间(尽量设置为大于10的值)</param>
        public static float UnTetheredLerp(float time = 10f)
        {
            return 1 - Mathf.Exp(-time * Time.deltaTime);
        }

        /// <summary>
        /// 阻力时间(可在Lerp函数中代替增量时间的使用)相比较DragTimeE，使用这个函数趋近目标值的速度会更快。
        /// 注意:在趋近与目标值时，变化会越来越小,不会真正抵达目标值,只会接近。
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static float DragTimeP(float time)
        {
            return 1 - Mathf.Pow(time ,Time.deltaTime);
        }
        

        #endregion
    }
}
